package com.laboratory.manage.controller;


import com.auth0.jwt.JWT;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.laboratory.manage.Exception.BizCodeEnum;
import com.laboratory.manage.Exception.EmailException;
import com.laboratory.manage.Exception.UserNameException;
import com.laboratory.manage.annotation.UserLoginToken;
import com.laboratory.manage.entity.UserEntity;
import com.laboratory.manage.service.SysCaptchaService;
import com.laboratory.manage.service.TokenService;
import com.laboratory.manage.service.UserService;
import com.laboratory.manage.utils.EmailUtil;
import com.laboratory.manage.utils.PageUtils;
import com.laboratory.manage.utils.R;
import com.laboratory.manage.vo.UserLoginVo;
import com.laboratory.manage.vo.UserRegisterVo;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.time.Duration;
import java.util.Map;
import java.util.Objects;


//@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private SysCaptchaService sysCaptchaService;

    /**
     * 用户登录
     * @param user
     * @return
     */
    @PostMapping("/login")
    public R login(@RequestBody UserLoginVo user){
        boolean captcha = sysCaptchaService.validate(user.getUuid(), user.getCaptcha());
        if(!captcha){
            return R.error("图片验证码不正确");
        }

        //根据用户名，查找用户信息
        UserEntity userEntity = userService.queryByUserName(user.getUsername());

        if(userEntity != null){

            //获取到数据库的密码
            String password = userEntity.getPassword();
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

            //进行密码匹配
            boolean matches = passwordEncoder.matches(user.getPassword(), password);
            if(!matches){
                // 如果最终的匹配结果是false
                return R.error(BizCodeEnum.LOGIN_ACCOUNT_PASSWORD_EXCEPTION.getCode(), BizCodeEnum.LOGIN_ACCOUNT_PASSWORD_EXCEPTION.getMsg());
            }

            //生成token令牌
            String token = tokenService.getToken(userEntity);

            //将token令牌，存到redis
            redisTemplate.opsForValue().set(userEntity.getId(), token, Duration.ofHours(24));
            return R.ok().setData(token);

        }else {
            return R.error(BizCodeEnum.LOGIN_ACCOUNT_PASSWORD_EXCEPTION.getCode(), BizCodeEnum.LOGIN_ACCOUNT_PASSWORD_EXCEPTION.getMsg());
        }
    }

    /**
     * 用户注册
     * @param vo
     * @return
     */
    @RequestMapping("/register")
    public R register(@RequestBody UserRegisterVo vo){
        try{
            System.out.println(" 注册用户发送的验证码 " + vo.getEmailCode());
            System.out.println(" redis中保存的验证码 " + redisTemplate.opsForValue().get(vo.getEmail()));
            if (vo.getEmailCode().equals(redisTemplate.opsForValue().get(vo.getEmail()))){

                //如果填写的邮箱和存放在redis里面的邮箱一致，那么就可以进行注册的操作。
                userService.register(vo);
            }else {
                return R.error(BizCodeEnum.EMAIL_CODE_INCORRECT_EXCEPTION.getCode(), BizCodeEnum.EMAIL_CODE_INCORRECT_EXCEPTION.getMsg());
            }
        }catch (EmailException e){
            return R.error(BizCodeEnum.EMAIL_EXIST_EXCEPTION.getCode(), BizCodeEnum.EMAIL_EXIST_EXCEPTION.getMsg());
        }catch (UserNameException e){
            return R.error(BizCodeEnum.USER_EXIST_EXCEPTION.getCode(), BizCodeEnum.USER_EXIST_EXCEPTION.getMsg());
        }
        return R.ok();
    }

    /**
     * 获取邮箱验证码
     * @param email
     * @return
     */
    @RequestMapping("/sendEmailCode")
    public R send(@RequestParam("email") String email){

        String[] to = new String[]{email};
        String subject = "验证码信息";

        //随机生成一个六位数的验证码
        String emailCode = EmailUtil.next();

        //要向邮箱发送的具体内容
        String text = "您好：\n    您正在注册边缘计算与虚拟现实实验室系统，邮箱验证码为: " + emailCode + "，验证码有效时长5分钟，请勿转发他人。";

        //将得到的这个验证码存起来放在redis里面 邮箱为key, 验证码为value
        redisTemplate.opsForValue().set(email, emailCode, Duration.ofMinutes(5));
        try{
            userService.sendEmail(to, subject, text);
            return R.ok("邮件发送成功");
        }catch (MailException e){
            e.printStackTrace();
            return R.error("邮件发送失败");
        }
    }

    /**
     * 用户登出
     * @param httpServletRequest
     * @return
     */
    @RequestMapping("/logout")
    public R logout(HttpServletRequest httpServletRequest){

        //使用jwt从request请求头里面取出来token
        String userId = JWT.decode(httpServletRequest.getHeader("token")).getAudience().get(0);

        //从redis中删除这个用户
        Boolean isDel = redisTemplate.delete(userId);

        //如果isDel为true代表已经删除
        if (isDel != null && isDel) {
            return R.ok("已删除");
        }else {
            return R.error("删除失败");
        }
    }

    /**
     * 修改用户信息
     * @param httpServletRequest
     * @param user
     * @return
     */
    @RequestMapping("/update")
    public R update(HttpServletRequest httpServletRequest, @RequestBody UserEntity user){

        //从http请求头中获取token
        String token = httpServletRequest.getHeader("token");

        //将token解码，并从token中获得用户id
        String userId = JWT.decode(token).getAudience().get(0);

        //如果redis里面存的token和请求头里面的token相同
        if(Objects.equals(redisTemplate.opsForValue().get(userId), token)){

            //条件查询控制器
            UpdateWrapper<UserEntity> updateWrapper = new UpdateWrapper<>();
            updateWrapper
                    .eq("id", userId)
                    .eq("username", user.getUsername())
                    .eq("email", user.getEmail())
                    .set("nickname", user.getNickname())
                    .set("phone", user.getPhone())
                    .set("postcode", user.getPostcode())
                    .set("area", user.getArea())
                    .set("qq", user.getQq());
            if(userService.update(updateWrapper)){
                return R.ok();
            }else {
                return R.error(14000, "用户信息更新失败");
            }
        }
        return R.error(14000, "用户身份校验失败");
    }

    /**
     * 用户列表 post方法
     */
    @PostMapping("/list")
    public R list(@RequestParam Map<String, Object> params){
        PageUtils page = userService.queryPage(params);

        return R.ok().put("page", page);
    }

    /**
     * 用户忘记密码，进行邮箱验证接口
     * @param user
     * @return
     */
    @RequestMapping("/findpassword")
    public R findPassword(@RequestBody UserEntity user){

        //首先根据，用户名和用户邮箱在数据库中查找这个用户
        boolean isFind = userService.findUserByNameAndEmail(user.getUsername(), user.getEmail());

        //如果找到了
        if(isFind){
            String[] to = new String[]{user.getEmail()};
            String subject = "验证码信息";

            //生成一个六位数的验证码
            String emailCode = EmailUtil.next();
            String text = "边缘计算虚拟现实门户网站提醒您：\n    您正在修改密码，验证码为: " + emailCode + "，验证码有效时长5分钟，请勿转发他人。";
            redisTemplate.opsForValue().set(user.getEmail(), emailCode, Duration.ofMinutes(5));
            try {
                userService.sendEmail(to,subject,text);
                return R.ok("邮件发送成功");
            } catch (MailException e) {
                e.printStackTrace();
                return R.error("邮件发送失败");
            }
        }
        return R.error(BizCodeEnum.ACCOUNT_MISMATCH_EMAIL_EXCEPTION.getCode(), BizCodeEnum.ACCOUNT_MISMATCH_EMAIL_EXCEPTION.getMsg());
    }

    /**
     * 验证，邮箱是否是合法的
     * @return
     */
    @RequestMapping("/validateEmailCode")
    public R validateEmailCode(@RequestBody UserRegisterVo vo){

        //判断redis中是否存在指定的键
        boolean hasKey = Objects.equals(redisTemplate.hasKey(vo.getEmail()), Boolean.TRUE);

        //如果存在这个键
        if (hasKey) {
            if (redisTemplate.opsForValue().get(vo.getEmail()).equals(vo.getCode())) {
                return R.ok().put("data", "邮箱验证码通过");
            }
        }
        return R.error(BizCodeEnum.EMAIL_CODE_INCORRECT_EXCEPTION.getCode(), BizCodeEnum.EMAIL_CODE_INCORRECT_EXCEPTION.getMsg());
    }

    /**
     * 通过邮箱，修改密码
     * @param vo
     * @return
     */
    @RequestMapping("/changePasswordByEmail")
    public R changePasswordByEmail(@RequestBody UserRegisterVo vo){
        boolean hasKey = Objects.equals(redisTemplate.hasKey(vo.getEmail()), Boolean.TRUE);
        if (hasKey) {
            if (redisTemplate.opsForValue().get(vo.getEmail()).equals(vo.getCode())) {
                // TODO 修改密码
                userService.changePasswordByEmail(vo);
                return R.ok();
            }
        }
        return R.error(BizCodeEnum.EMAIL_CODE_INCORRECT_EXCEPTION.getCode(), BizCodeEnum.EMAIL_CODE_INCORRECT_EXCEPTION.getMsg());
    }

    /**
     * 通过token获取用户信息
     */
    @UserLoginToken
    @RequestMapping(value = "/getinfo")
    public R info(HttpServletRequest httpServletRequest){
        String token = httpServletRequest.getHeader("token");
        String userId = JWT.decode(token).getAudience().get(0);
        if(Objects.equals(redisTemplate.opsForValue().get(userId), token)){
            UserEntity user = userService.getById(userId);
            return R.ok().put("data", user);
        }
        else {
            return R.error(BizCodeEnum.TOKEN_EXPIRED_EXCEPTION.getCode(), BizCodeEnum.TOKEN_EXPIRED_EXCEPTION.getMsg());
        }
    }

    /**
     * 获取图片验证码
     */
    @GetMapping("captcha.jpg")
    public void captcha(HttpServletResponse response, String uuid) throws IOException {

        //设置响应头，禁用缓存
        response.setHeader("Cache-Control", "no-store, no-cache");

        //设置响应内容为图片类型
        response.setContentType("image/jpeg");

        //获取图片验证码
        BufferedImage image = sysCaptchaService.getCaptcha(uuid);

        //获取响应输出流
        ServletOutputStream out = response.getOutputStream();

        //将验证码图片写入响应输出流中，以jpg格式输出
        ImageIO.write(image, "jpg", out);

        //关闭输出流
        IOUtils.closeQuietly(out);
    }

}
